/*
 * Copyright (C) 2012 Michael L.R. Marques
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * Contact: michaellrmarques@gmail.com
 */

package com.jm.commons.models;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

/**
 * This class recieves a {@code ResultSet} and populates a {@code JTable}
 * with the contents of the {@code ResultSet}. A TYPE_SCROLL_SENSITIVE
 * and CONCOR_READ_ONLY {@code ResultSet} is required.
 * 
 * 
 */
public class ResultSetTableModel implements TableModel {
    
    /**
     * The result set object
     */
    private ResultSet results;
    
    /**
     * The number of rows (re-counting the rows in the result is expensive, so just save it)
     */
    private int rows;
    
    /**
     * The collection of columns (re-collecting the columns from the result set is expensive)
     */
    private List<String> columns;
    
    /**
     * Creates the {@code ResultSetTableModel}
     * @param results
     * @param type
     * @throws SQLException
     * @throws OutOfMemoryError
     */
    public ResultSetTableModel(ResultSet results) throws SQLException, OutOfMemoryError {
        // Set the columns
        ResultSetMetaData rsmd = results.getMetaData();
        this.columns = new ArrayList();
        for (int i = 1; i <= rsmd.getColumnCount(); i++) {
            this.columns.add(rsmd.getColumnName(i));
        }
        // Gets the number of rows
        results.last();
        this.rows = results.getRow();
        results.first();
        // Sets the result set
        this.results = results;
    }
    
    /**
     * Get column count
     * 
     * @return int
     */
    @Override public int getColumnCount() {
        return this.columns.size();
    }
    
    /**
     * Get row count
     * 
     * @return int
     */
    @Override public int getRowCount() {
        return this.rows;
    }
    
    /**
     * Gets the column name from the columns collection
     * 
     * @param column
     * @return String
     */
    @Override public String getColumnName(int column) {
        return this.columns.get(column);
    }
    
    /**
     * Returns the column type as an {@code Object}
     * 
     * @param column
     * @return Class
     */
    @Override public Class getColumnClass(int column) {
        return Object.class;
    }
    
    /**
     * Gets the value from the result set
     * If the @code{JTable} is trying to request a value
     * from the same current row, do not call the absolute
     * method again as this can be taxing on the result set
     * 
     * @param row
     * @param column
     * @return Object
     */
    @Override public Object getValueAt(int row, int column) {
        try {
            // Only call the absolute method if we are not on the correct row
            if(this.results.getRow() != row + 1) {
                this.results.absolute(row + 1);
            }
            // Get the column by the generic @code{Object} type
            return this.results.getObject(column + 1);
        } catch(SQLException sqle) {
            System.out.println(sqle.getMessage());
            return null;
        }
    }
    /**
     * The table is not editable
     * 
     * @param row
     * @param column
     * @return false
     */
    @Override public boolean isCellEditable(int row, int column) {
        return false;
    }
    /**
     * Not needed
     * 
     * @param value
     * @param row
     * @param column
     */
    @Override public void setValueAt(Object value, int row, int column) {}
    
    /**
     * Not needed
     * 
     * @param l
     */
    @Override public void addTableModelListener(TableModelListener l) {}
    
    /**
     * Not needed
     * 
     * @param l
     */
    @Override public void removeTableModelListener(TableModelListener l) {}
    
}
